﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Compilex.Syntatic.Declarations
{
    public static class SymbolTableHelper
    {
        public static void AssertVariableUndeclaredCurrentScope(string id, SyntaticContext context)
        {
            if (context.ScopeManager.CurrentScope.IsDeclaredHere(SymbolClass.Variavex, id)
                || context.ScopeManager.CurrentScope.IsDeclaredHere(SymbolClass.Vetex, id))
                throw new SyntaticException("A variável \"" + id + "\" já foi declarada.");
        }

        public static void AssertUserDefinedTypeExists(string typeId, SyntaticContext context)
        {
            if (!context.ScopeManager.CurrentScope.IsDeclaredAnywhere(SymbolClass.Estruturex,
                typeId))
            {
                throw new SyntaticException("A estrutura \"" + typeId + "\" não foi declarada.");
            }
        }

        public static void AssertUserDefinedTypeExists(SymbolType type, SyntaticContext context)
        {
            if (type.TypeValue == TypeValue.userDefined)
            {
                if (!context.ScopeManager.CurrentScope.IsDeclaredAnywhere(SymbolClass.Estruturex,
                    type.UserDefinedTypeName))
                {
                    throw new SyntaticException("A estrutura \"" + type.UserDefinedTypeName + "\" não foi declarada.");
                }
            }
        }

        public static void AssertFunctionIdentifierUndeclared(string id, SyntaticContext context)
        {
            if (context.ScopeManager.CurrentScope.IsDeclaredHere(SymbolClass.Funcex, id))
                throw new SyntaticException("A função \"" + id + "\" já foi declarada.");
        }

        public static void AssertFunctionIdentifierDeclared(string id, SyntaticContext context)
        {
            if (!context.ScopeManager.CurrentScope.IsDeclaredAnywhere(SymbolClass.Funcex, id))
                throw new SyntaticException("A função \"" + id + "\" não foi declarada.");
        }

        public static SymbolType SymbolTypeFromString(string typeName, SyntaticContext context)
        {
            SymbolType symbol = SymbolType.FromString(typeName);
            if (symbol.TypeValue == TypeValue.userDefined)
                AssertUserDefinedTypeExists(symbol.UserDefinedTypeName, context);
            return symbol;
        }

        public static Symbol GetVariableDeclaredAnywhere(string symbolId, SyntaticContext context)
        {
            Symbol symbol = context.ScopeManager.CurrentScope.TryGetDeclarationAnywhere(
                SymbolClass.Variavex, symbolId);
            if (symbol == null)
            {
                throw new SyntaticException("A variável " + symbolId + " não foi declarada.");
            }
            else
                return symbol;
        }

        public static Symbol GetArrayDeclaredAnywhere(string symbolId, SyntaticContext context)
        {
            Symbol symbol = context.ScopeManager.CurrentScope.TryGetDeclarationAnywhere(
                SymbolClass.Vetex, symbolId);
            if (symbol == null)
            {
                throw new SyntaticException("O vetor " + symbolId + " não foi declarado.");
            }
            else
                return symbol;
        }


        public static Symbol TryGetVariableDeclaredAnywhere(string symbolId, SyntaticContext context)
        {
            return context.ScopeManager.CurrentScope.TryGetDeclarationAnywhere(
                SymbolClass.Variavex, symbolId);
        }

        public static bool IsGlobalSymbol(Symbol symbol, SyntaticContext context)
        {
            Scope declaringScope = context.ScopeManager.CurrentScope.GetDeclaringScope(
                symbol.Class,  symbol.Identifier);

            if (declaringScope != null)
                return declaringScope.ParentScope == null;
            else
                throw new InternalSyntaticException("Símbolo " + symbol.Identifier + " não está declarado em lugar nenhum.");
        }

    }
}
